/**
* Copyright (C) 2000-2016 Atomikos <info@atomikos.com>
*
* LICENSE CONDITIONS
*
* See http://www.atomikos.com/Main/WhichLicenseApplies for details.
*/
package com.atomikos.jdbc;
import java.util.Properties;
import java.util.Set;
import javax.sql.XADataSource;
import com.atomikos.beans.PropertyUtils;
import com.atomikos.datasource.RecoverableResource;
import com.atomikos.datasource.xa.event.XAResourceDetectedEvent;
import com.atomikos.datasource.xa.jdbc.JdbcTransactionalResource;
import com.atomikos.icatch.config.Configuration;
import com.atomikos.logging.Logger;
import com.atomikos.logging.LoggerFactory;
import com.atomikos.publish.EventPublisher;
import com.atomikos.util.ClassLoadingHelper;
/**
* The preferred class for using Atomikos connection pooling. Use an instance of
* this class if you want to use Atomikos JTA-enabled connection pooling. All
* you need to do is construct an instance and set the required properties as
* outlined below. The resulting bean will automatically register with the
* transaction service (for recovery) and take part in active transactions.
* All SQL done over connections (gotten from this class) will participate in JTA transactions.
*/
public class AtomikosDataSourceBean
extends AbstractDataSourceBean
{
private static final Logger LOGGER = LoggerFactory.createLogger(AtomikosDataSourceBean.class);
private static final long serialVersionUID = 1L;
private Properties xaProperties = null;
private String xaDataSourceClassName;
private transient XADataSource xaDataSource;
public AtomikosDataSourceBean()
{
this.xaProperties = new Properties();
}
private String printXaProperties()
{
StringBuffer ret = new StringBuffer();
if ( xaProperties != null ) {
Set<String> names = xaProperties.stringPropertyNames();
ret.append ( "[" );
boolean first = true;
for (String name : names) {
if ( ! first ) ret.append ( "," );
String value = xaProperties.getProperty( name);
ret.append ( name ); ret.append ( "=" ); ret.append ( value );
first = false;
}
ret.append ( "]" );
}
return ret.toString();
}
/**
* Gets the properties used to
* configure the XADataSource.
*/
public Properties getXaProperties()
{
return xaProperties;
}
/**
* Sets the properties (name,value pairs) used to
* configure the XADataSource. Required, unless you call setXaDataSource directly.
*
* @param xaProperties
*
*
*/
public void setXaProperties ( Properties xaProperties )
{
this.xaProperties = xaProperties;
}
/**
* Get the XADataSource class name.
*/
public String getXaDataSourceClassName()
{
return xaDataSourceClassName;
}
/**
* Sets the fully qualified underlying XADataSource class name. Required, unless you
* call setXaDataSource directly.
*
* @param xaDataSourceClassName
*/
public void setXaDataSourceClassName ( String xaDataSourceClassName )
{
this.xaDataSourceClassName = xaDataSourceClassName;
}
/**
* Gets the configured XADataSource (if any).
* @return The instance, or null if none.
*/
public XADataSource getXaDataSource()
{
return xaDataSource;
}
/**
* Sets the XADataSource directly - instead of providing the xaDataSourceClassName and xaProperties.
* @param xaDataSource
*/
public void setXaDataSource(XADataSource xaDataSource)
{
this.xaDataSource = xaDataSource;
}
protected com.atomikos.datasource.pool.ConnectionFactory doInit() throws Exception
{
if (xaDataSource == null)
{
if (xaDataSourceClassName == null)
throwAtomikosSQLException("Property 'xaDataSourceClassName' cannot be null");
if (xaProperties == null)
throwAtomikosSQLException("Property 'xaProperties' cannot be null");
}
if ( LOGGER.isDebugEnabled() ) LOGGER.logInfo(
this + ": initializing with [" +
" xaDataSourceClassName=" + xaDataSourceClassName + "," +
" uniqueResourceName=" + getUniqueResourceName() + "," +
" maxPoolSize=" + getMaxPoolSize() + "," +
" minPoolSize=" + getMinPoolSize() + "," +
" borrowConnectionTimeout=" + getBorrowConnectionTimeout() + "," +
" maxIdleTime=" + getMaxIdleTime() + "," +
" reapTimeout=" + getReapTimeout() + "," +
" maintenanceInterval=" + getMaintenanceInterval() + "," +
" testQuery=" + getTestQuery() + "," +
" xaProperties=" + printXaProperties() + "," +
" loginTimeout=" + getLoginTimeout() + "," +
" maxLifetime=" + getMaxLifetime() +
"]"
);
if (xaDataSource == null)
{
try {
Class<XADataSource> xadsClass = ClassLoadingHelper.loadClass ( getXaDataSourceClassName() );
xaDataSource = xadsClass.newInstance();
} catch ( ClassNotFoundException nf ) {
AtomikosSQLException.throwAtomikosSQLException ( "The class '" + getXaDataSourceClassName() +
"' specified by property 'xaDataSourceClassName' could not be found in the classpath. Please make sure the spelling is correct, and that the required jar(s) are in the classpath." , nf );
} catch (ClassCastException cce) {
AtomikosSQLException.throwAtomikosSQLException (
"The class '" + getXaDataSourceClassName() +
"' specified by property 'xaDataSourceClassName' does not implement the required interface javax.jdbc.XADataSource. Please make sure the spelling is correct, and check your JDBC driver vendor's documentation.");
}
xaDataSource.setLoginTimeout ( getLoginTimeout() );
xaDataSource.setLogWriter ( getLogWriter() );
PropertyUtils.setProperties(xaDataSource, xaProperties );
}
JdbcTransactionalResource tr = new JdbcTransactionalResource(getUniqueResourceName() , xaDataSource);
com.atomikos.datasource.pool.ConnectionFactory cf = new com.atomikos.jdbc.AtomikosXAConnectionFactory(xaDataSource, tr, this);
Configuration.addResource ( tr );
EventPublisher.publish(new XAResourceDetectedEvent(xaDataSourceClassName,xaProperties,XAResourceDetectedEvent.ResourceType.JDBC));
return cf;
}
protected void doClose()
{
RecoverableResource res = Configuration.getResource ( getUniqueResourceName() );
if ( res != null ) {
Configuration.removeResource ( getUniqueResourceName() );
//fix for case 26005
res.close();
}
}
public String toString()
{
String ret = "AtomikosDataSoureBean";
String name = getUniqueResourceName();
if ( name != null ) {
ret = ret + " '" + name + "'";
}
return ret;
}
protected boolean isAssignableFromWrappedVendorClass(Class<?> iface) {
boolean ret = false;
if (xaDataSource != null ) {
ret = iface.isAssignableFrom(xaDataSource.getClass());
}
return ret;
}
@Override
protected Object unwrapVendorInstance() {
return xaDataSource;
}
}